﻿#region

using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;

#endregion

namespace Pob.ScreenManagement
{
    public class ScreenManager : DrawableGameComponent
    {
        #region Fields

        private readonly List<ScreenBase> _screens = new List<ScreenBase>();

        private readonly List<ScreenBase> _screensToDispose = new List<ScreenBase>();

        private readonly List<ScreenBase> _screensToUpdate = new List<ScreenBase>();

        #endregion

        #region Constructors and Destructors

        public ScreenManager(Game game)
            : base(game)
        {
        }

        #endregion

        #region Public Methods and Operators

        public void Add(ScreenBase newScreen, bool isPopup = false)
        {
            newScreen.ScreenManager = this;
            newScreen.IsExiting = false;
            newScreen.Initialize();

            if (isPopup)
            {
                foreach (var screen in _screens)
                {
                    screen.Pause();
                }
            }

            _screens.Add(newScreen);
        }

        public void Clear()
        {
            foreach (var screen in _screens)
            {
                foreach (var obj in screen.MyComponents)
                {
                    Game.Components.Remove(obj);
                    obj.Dispose();
                }

                _screensToDispose.Add(screen);
            }

            _screens.Clear();
            _screensToUpdate.Clear();
        }

        public override void Initialize()
        {
            SettingsManager.CurrentInstance.SetDefaultValues();

            base.Initialize();
        }

        public void Remove(ScreenBase oldScreen, bool isPopup = false)
        {
            foreach (var obj in oldScreen.MyComponents)
            {
                Game.Components.Remove(obj);
                obj.Dispose();
            }

            _screens.Remove(oldScreen);
            _screensToUpdate.Remove(oldScreen);
            _screensToDispose.Add(oldScreen);

            if (isPopup)
            {
                foreach (var screen in _screens)
                {
                    screen.Resume();
                }
            }
        }

        public override void Update(GameTime gameTime)
        {
            foreach (var screen in _screensToDispose)
            {
                screen.Dispose();
            }

            _screensToDispose.Clear();

            foreach (var screen in _screens.Where(screen => screen.Enabled))
            {
                _screensToUpdate.Add(screen);
            }

            while (_screensToUpdate.Count > 0)
            {
                ScreenBase screen = _screensToUpdate[_screensToUpdate.Count - 1];

                _screensToUpdate.RemoveAt(_screensToUpdate.Count - 1);

                screen.Update(gameTime);
            }
        }

        #endregion
    }
}